package com.fingard.dsp.bank.directbank.hsbc02;

import com.alibaba.fastjson.JSONObject;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import com.fingard.util.BouncyCastlePgpHelper;
import com.fingard.util.TransIDHelper;
import com.fingard.xml.XmlTextWriter;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.FileInputStream;
import java.util.Date;

/**
 * 汇丰银行api接口公共方法
 */
public class HSBC02Base extends DirectBase {

    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    private static TransIDHelper idHelper = new TransIDHelper(1, 999);

    protected String getQryTransID() {
        Date tmpDateNow = new Date();
        return Format.DateTime12Year2Format.format(tmpDateNow) + idHelper.getNextIDStr();
    }

    /**
     * 发送报文至银行
     *
     * @param p_reqStr 请求报文
     * @return
     * @throws Exception
     */
    protected String[] sendToBank(String p_reqStr, String typeName,String commandCode,String param) throws Exception {
        String[] retStrArr = new String[]{"","",""};
        try {
            WriteBankLogLn("请求数据原文：\r\n" + p_reqStr);
            //0、后置挡板
            if(StringHelper.hasAnyChar(typeName) && StringHelper.hasAnyChar(commandCode)) {
                this.detailSimulateForBank(bankFront.bankCode, typeName, commandCode, p_reqStr, retStrArr);
                if (retStrArr[1].length() > 0) {
                    retStrArr[2]="{\"referenceId\":\"f596658e-bca7-4030-9d4d-c0d16803646f\",\"profileId\":\"PC000017283\"" +
                            ",\"statusCode\":\"ACCP\",\"statusDesc\":\"Accepted Instruction Validation (L2)\",\"responseBase64\":\"\"}";
                    return retStrArr;
                }
            }
            //1、PGP数据加密/签名 base64编码
            String reqGpg = pgpEncryptSigned(p_reqStr);
            BASE64Encoder encoder=new BASE64Encoder();
            String reqBase64=encoder.encode(reqGpg.getBytes());
            JSONObject reqJsonBase64 = new JSONObject();
            reqJsonBase64.put(param, reqBase64.replaceAll("\r\n",""));
            WriteBankLogLn("PGP数据加密后base64加密的请求报文：\r\n" + reqBase64.replaceAll("\r\n",""));
            //2、发起请求
            String url=StringHelper.trimEndFileSp(bankFront.serverURL);
            String payloadType="";
            if("7506".equals(typeName)){
                url+= "/cmb-connect-payments-pa-account-cert-proxy/v2/balances";
                payloadType="JSON";
            }else if("7516".equals(typeName) || "7515".equals(typeName)){
                url+= "/cmb-connect-payments-pa-account-cert-proxy/v2/transactions";
                payloadType="JSON";
            }else if("1908".equals(typeName)){
                url+= "/cmb-connect-payments-pa-payment-cert-proxy/v1/payments/instant-receipt";
                payloadType="pain.001.001.03";
            }else if("1944".equals(typeName)){
                url+= "/cmb-connect-payments-pa-payment-cert-proxy/v1/payments/status";
                payloadType="pain.002.001.03";
            }
            WriteBankLogLn("1.提交银行的地址：" + url);
            String p_string = reqJsonBase64.toJSONString();
            WriteBankLogStep2(p_string);
            System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
            WebRequest tmpWebRequest = new WebRequest(url);
            tmpWebRequest.setConnectTimeout(60000);
            tmpWebRequest.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            tmpWebRequest.setRequestProperty("x-hsbc-client-id",
                    getBankConfig().getValueAsString("x-hsbc-client-id"));
            tmpWebRequest.setRequestProperty("x-hsbc-client-secret",
                    getBankConfig().getValueAsString("x-hsbc-client-secret"));
            tmpWebRequest.setRequestProperty("x-hsbc-profile-id",
                    getBankConfig().getValueAsString("x-hsbc-profile-id"));
            if("1908".equals(typeName)){
                tmpWebRequest.setRequestProperty("x-payload-type", payloadType);
            }else {
                tmpWebRequest.setRequestProperty("x-report-type", payloadType);
            }
            tmpWebRequest.setBankFront(this.bankFront);
            byte[] tmpToWriteBytes = p_string.getBytes(getCharset());
            String[] retStr = tmpWebRequest.upload(tmpToWriteBytes, getCharset());
            WriteBankLogStep3(retStr[1]);
            //3、解密验签响应报文，返回原文
            if (retStr[0].length() == 0) {
                JSONObject jsonRsp = JSONObject.parseObject(retStr[1]);
                String rspCode = StringHelper.hasAnyChar(jsonRsp.getString("statusCode"))
                        ? jsonRsp.getString("statusCode") : jsonRsp.getString("error");
                String rspMesg = StringHelper.hasAnyChar(jsonRsp.getString("statusDesc"))
                        ? jsonRsp.getString("statusDesc") : jsonRsp.getString("description");
                String responseBase64=jsonRsp.getString("responseBase64");
                if(StringHelper.hasAnyChar(responseBase64)){
                    BASE64Decoder decoder = new BASE64Decoder();
                    String rspBase64 = new String(decoder.decodeBuffer(responseBase64));
                    if("1908".equals(typeName) || "1944".equals(typeName)){
                        //pgp解密验签
                        String decryptRsp = pgpDecryptAndVerify(rspBase64);
                        retStrArr[1]=decryptRsp;
                        retStrArr[2]=jsonRsp.toJSONString();
                        WriteBankLogLn("解密解签后的响应内容：\r\n" + decryptRsp);
                    }else {
                        if ("ACCP".equals(rspCode)) {//查询成功
                            //pgp解密验签
                            String decryptRsp = pgpDecryptAndVerify(rspBase64);
                            retStrArr[1]=decryptRsp;
                            WriteBankLogLn("解密解签后的响应内容：\r\n" + decryptRsp);
                        }else {
                            retStrArr[0]="-1";
                            retStrArr[1]=rspMesg;
                        }
                    }
                }else {
                    retStrArr[0]="-1";
                    retStrArr[1]=rspMesg;
                }
            }else {
                retStrArr[0]="-1";
                retStrArr[1]=retStr[1];
            }
        } catch (Exception e) {
            WriteBankLogLn("请求到银行异常:" + e);
            retStrArr[0] = "E9999";
            retStrArr[1] = e.getMessage();
            e.printStackTrace();
        }
        return retStrArr;
    }

    protected void WriteCommonHeader(XmlTextWriter xmlWriter) throws Exception {
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\""+getCharset()+"\"?>");
        xmlWriter.writeElementAttribute("Document","xmlns",
                "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03\"" +
                        " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance");
        xmlWriter.writeStartElement("CstmrCdtTrfInitn");
    }

    /**
     * PGP加密加签
     *
     * @param data 待加密加签数据
     * @return
     * @throws Exception
     */
    protected String pgpEncryptSigned(String data) throws Exception{
        String bankPubFilePath=getBankConfig().getValueAsString("bankPubPath");
        String orgPrvFilePath=getBankConfig().getValueAsString("orgPrvPath");
        String passwd=getBankConfig().getValueAsString("orgPrvPassWord");
        //银行公钥
        PGPPublicKey dbsPubKey = BouncyCastlePgpHelper.readPublicKey(new FileInputStream(bankPubFilePath));
        //企业私钥
        PGPSecretKey glpSecretKey = BouncyCastlePgpHelper.readSecretKey(new FileInputStream(orgPrvFilePath));
        //企业私钥密码
        PGPPrivateKey glpPrivateKey = BouncyCastlePgpHelper.findPrivateKey(new FileInputStream(orgPrvFilePath)
                , passwd.toCharArray());
        //加密加签
        return BouncyCastlePgpHelper.encryptSigned(data, dbsPubKey, glpSecretKey, glpPrivateKey);
    }

    /**
     * PGP解密验签 待解密解签数据
     *
     * @param signData
     * @return
     * @throws Exception
     */
    protected String pgpDecryptAndVerify(String signData) throws Exception{
        String bankPubFilePath=getBankConfig().getValueAsString("bankPubPath");
        String orgPrvFilePath=getBankConfig().getValueAsString("orgPrvPath");
        String passwd=getBankConfig().getValueAsString("orgPrvPassWord");
        //解密解签
        return BouncyCastlePgpHelper.decryptAndVerify(bankPubFilePath,orgPrvFilePath
                ,passwd.toCharArray(),signData,getCharset());
    }

    /**
     * 根据账号和日期查询明细数据
     * @param actNum 查询账号
     * @param transDate 查询日期yyyyMMdd
     * @return
     * @throws Exception
     */
    protected String[] qryTransactionJson(String actNum,String transDate) throws Exception{
        String[] decryptRsp=new String[]{"",""};//响应的明细数据
        JSONObject transReqJson = new JSONObject();
        transReqJson.put("accountNumber",actNum);//Account Number. Max length 34
        transReqJson.put("accountCountry",getBankConfig().getMapValueByKey("balanceAndConturyMapping",actNum));
        transReqJson.put("accountType","CA");//Account Type i.e CA
        transReqJson.put("institutionCode","HBAP");//Institution Code i.e HBAP
        transReqJson.put("transactionDate",transDate);//ISO 8601 format in UTC, such as yyyy-mm-dd i.e. 2019-05-08
        transReqJson.put("transactionTimeFrom","");//Applicable for Current Date only. The time in 24-hour clock system
        transReqJson.put("transactionTimeTo","");//Applicable for Current Date only. The time in 24-hour clock system
        //发送请求报文
        String[] bankResult = sendToBank(transReqJson.toJSONString(),"7516","7516","transactionsRequestBase64");
        //处理响应报文
        if (bankResult[0].length() == 0) {
            decryptRsp[1] = bankResult[1];
        }else {
            decryptRsp[0]="RJCT";
            decryptRsp[1]=bankResult[1];
        }
        return decryptRsp;
    }
}
